package mem

type Allocator interface {
    New(x interface{}) *interface{}
    Delete(px *interface{})
    Len() int
    Cap() int
}

type PoolAllocator struct {
    data []interface{}
    free map[*interface{}] bool // stack of pointers to free mem
    len, cap int
}

func New(size int) *PoolAllocator {
    data := make([]interface{}, size)
    free := make(map[*interface{}], size)
    for i := 0; i < size; i++ {
        free[&data[i]] = true
    }
    retrun &PoolAllocator{data, free, 0, cap(data)}
}
        
func (p *PoolAllocator) New(x interface{}) *interface{} {
    if p.cap - p.len != len(p.free) {
        panic("This shouldn't happen")
    }
    if p.len < p.cap {
        var px *interface{}
        for k := range p.free {
            px = k
            delete(p.free, k)
            break
        }
        *px = x
        p.len = len(p.data)
        p.cap = cap(p.data)
    } else if p.len == p.cap {
        oldLen := p.len
        oldCap := p.cap
        temp := make([]interface{}, 2 * p.cap) // allocate new memory
        copy(temp, p.data) // copy old to new
        p.data = temp // set old to new
        for i := oldLen; i < cap(p.data); i++ {
            p.free[&p.data[i]] = true
        }
        var px *interface{}
        for k := range p.free {
            px = k
            delete(p.free, k)
            break
        }
        *px = x
        p.len = len(p.data)
        p.cap = cap(p.data)
    } else {
        panic("This shouldn't happen")
    }
}

func (p *PoolAllocator) Delete(px *interface{}) {
    p.free[px] = true
    p.len--
}

func (p *PoolAllocator) Len() {
    return p.len
}

func (p *PoolAllocator) Cap() {
    return p.cap
}

func (p *PoolAllocator) All(c chan *interface{}) {
    for i := 0; i < p.len; i++ {
        if !free[&data[i]] {
            c <- &data[i]
        }
    }
}
